﻿/*
 * Created by SharpDevelop.
 * User: Administrator
 * Date: 2016/4/20
 * Time: 14:53
 *
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using SharpChannel.Core.Packet;
using SharpChannel.Util;

namespace SharpChannel.Core.Coder
{
	/// <summary>
	/// Description of SharpCoder.
	/// </summary>
	public class DefaultSharpCoder : SharpSingleton<DefaultSharpCoder>, ICoder
	{
        private static int ParseHeaderSize10(byte[] headers, IBufferQueue<byte> bufferQueue)
        {
			if(headers[1] != (byte)'1' || headers[2] != (byte)'0' || headers[3] != 0){
				bufferQueue.Clear();
				return 0;
			}

			var size = BitConverter.ToInt32(headers, 4);
		    if (size >= 0) return bufferQueue.ReadableSize() >= size ? size : 0;
		    bufferQueue.Clear();
		    return 0;

        }

        private static void EncoderHeader10(byte[] bytes, int size)
        {
			bytes[0] = CODER_VERSION_10;
			bytes[1] = (byte)'1';
			bytes[2] = (byte)'0';
			bytes[3] = 0;
			Array.Copy(BitConverter.GetBytes(size), 0, bytes, 4, 4);
        }

		private static int ParseNextHeaderSize(IBufferQueue<byte> bufferQueue){

			var headers = bufferQueue.Slice(0, HEADER_SIZE);
			if(headers == null || headers.Length < HEADER_SIZE) return 0;
            switch (headers[0])
            {
                case CODER_VERSION_10:
                    return ParseHeaderSize10(headers, bufferQueue);
                default:
                    LoggerHelper.GetLogger().Error("header version :" + headers[0] + " not implemented!");
                    bufferQueue.Clear();
                    return 0;
            }
		}

		#region ICoder implementation

		public bool CanDecode(IBufferQueue<byte> bufferQueue)
		{
			return ParseNextHeaderSize(bufferQueue) > 0;
		}

		public byte[] Decode(IBufferQueue<byte> bufferQueue)
		{
			var size = ParseNextHeaderSize(bufferQueue);
			return size >= HEADER_SIZE ? bufferQueue.DeQueue(HEADER_SIZE, size - HEADER_SIZE) : null;
		}

		public byte[] Encode(byte[] buffer, int offset = 0, int length = -1)
		{
			length = length < 0 ? buffer.Length - offset : length;
			length = Math.Min(buffer.Length - offset, length);
			var result = new byte[length + HEADER_SIZE];
            EncoderHeader10(result, result.Length);
			Array.Copy(buffer, offset, result, HEADER_SIZE, length);
			return result;
		}
		#endregion

		public const byte CODER_VERSION_10 = 10;
		public const int HEADER_SIZE = 8;
	}
}
